package cn.gov.pbc.exam.service.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import com.alibaba.excel.EasyExcel;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;

import cn.gov.pbc.exam.bo.UserBo;
import cn.gov.pbc.exam.common.QuestionConst;
import cn.gov.pbc.exam.common.ResponseCode;
import cn.gov.pbc.exam.common.ServerResponse;
import cn.gov.pbc.exam.dao.AnswerLogMapper;
import cn.gov.pbc.exam.dao.AnswerMapper;
import cn.gov.pbc.exam.dao.QuestionMapper;
import cn.gov.pbc.exam.dto.UserDto;
import cn.gov.pbc.exam.excel.QuestionDto;
import cn.gov.pbc.exam.excel.QuestionExcelDto;
import cn.gov.pbc.exam.excel.QuestionExcelListener;
import cn.gov.pbc.exam.pojo.Answer;
import cn.gov.pbc.exam.pojo.AnswerLog;
import cn.gov.pbc.exam.pojo.Question;
import cn.gov.pbc.exam.service.IQuestionService;
import cn.gov.pbc.exam.vo.OptionVo;
import cn.gov.pbc.exam.vo.QuestionCheckVo;
import cn.gov.pbc.exam.vo.QuestionVo;
import lombok.extern.slf4j.Slf4j;

@Service("iQuestionService")
@Slf4j
public class QuestionServiceImpl implements IQuestionService {

	@Autowired
	private QuestionMapper questionMapper;

	@Autowired
	private AnswerMapper answerMapper;

	@Autowired
	private AnswerLogMapper answerLogMapper;

	@Override
	public ServerResponse<?> getQuestion(UserBo userBo, UserDto userDto) {
		ServerResponse<?> response = userDto.validate();
		if (!response.isSuccess()) {
			return response;
		}

		Question question = this.getQuestionRandom();
		if (question == null) {
			return ServerResponse.createByErrorMessage("无法获取题目，请联系管理员");
		}
		List<Answer> answerList = this.answerMapper.selectAnswerByQuestionId(question.getId());
		if (answerList == null || answerList.size() == 0) {
			return ServerResponse.createByErrorMessage("题目错误，请联系管理员");
		}
		QuestionVo questionVo = this.assmbleQuestionVo(question, answerList);
		userBo.setUserName(userDto.getUser());
		userBo.setDeptName(userDto.getDept());
		userBo.setQuestion(question);
		userBo.setAnswerList(answerList);
		return ServerResponse.createBySuccess(questionVo);

	}

	private QuestionVo assmbleQuestionVo(Question question, List<Answer> answerList) {
		QuestionVo vo = new QuestionVo();
		vo.setId(question.getId());
		vo.setQuestionContent(question.getContent());
		vo.setType(question.getType());
		vo.setTypeMsg(QuestionConst.Type.codeOf(question.getType()).getValue());

		List<OptionVo> optionVoList = new ArrayList<>();
		vo.setOptionVoList(optionVoList);

		answerList.forEach(item -> {
			OptionVo optionVo = new OptionVo();
			optionVo.setId(item.getId());
			optionVo.setContent(item.getContent());
			optionVo.setQuestionId(item.getQuestionId());
			optionVo.setTitle(item.getTitle());
			optionVoList.add(optionVo);
		});

		return vo;
	}

	/**
	 * 随机获取一个问题
	 * 
	 * @return
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private Question getQuestionRandom() {
		int questionCount = this.questionMapper.selectQuestionCounter();
		int pageNum = new Random().nextInt(questionCount) + 1;
		if (pageNum == 0) {
			return null;
		}
		PageHelper.startPage(pageNum, 1);
		List<Question> questionList = this.questionMapper.selectAll();
		if (questionList == null || questionList.size() == 0) {
			return null;
		}
		PageInfo pageResult = new PageInfo(questionList);
		pageResult.setList(questionList);
		return questionList.get(0);
	}

	@Override
	public ServerResponse<?> checkAnswer(UserBo userBo, String selection) {
		if (StringUtils.isBlank(selection)) {
			return ServerResponse.createByErrorMessage("请选择答案后提交");
		}
		String[] selectionStr = selection.split(QuestionConst.SELECTION_SEPARATOR);
		// 校验用户上传的选项数量与题目类型是符合,如查为单选或者判断题，那么用户选择的数量肯定为1
		if (userBo.getQuestion().getType() == QuestionConst.Type.JUDGE.getCode()
				|| userBo.getQuestion().getType() == QuestionConst.Type.SINGLE.getCode()) {
			if (selectionStr.length != 1) {
				return ServerResponse.createByErrorCodeMessage(ResponseCode.ILLEGAL_ARGUMENT.getCode(),
						ResponseCode.ILLEGAL_ARGUMENT.getDesc());
			}
		}

		List<Integer> selectionId = new ArrayList<>();
		try {
			for (String item : selectionStr) {
				selectionId.add(Integer.valueOf(item));
			}
		} catch (NumberFormatException e) {
			log.error("用户上传的选项错误");
			return ServerResponse.createByErrorCodeMessage(ResponseCode.ILLEGAL_ARGUMENT.getCode(),
					ResponseCode.ILLEGAL_ARGUMENT.getDesc());
		}
		QuestionCheckVo questionCheckVo = this.checkResult(userBo, selectionId);
		ServerResponse<?> response = this.inserAnswerLog(userBo, questionCheckVo, selection);
		if (!response.isSuccess()) {
			return response;
		}
		return ServerResponse.createBySuccess(questionCheckVo);
	}

	private ServerResponse<?> inserAnswerLog(UserBo userBo, QuestionCheckVo questionCheckVo, String selection) {
		AnswerLog answerLog = new AnswerLog();
		answerLog.setDeptName(userBo.getDeptName());
		answerLog.setQuestionId(userBo.getQuestion().getId());
		answerLog.setResult(questionCheckVo.getCheckResult());
		answerLog.setUserName(userBo.getUserName());
		if (questionCheckVo.getCheckResult() == QuestionConst.CheckResult.WRONG.getCode()) {
			answerLog.setWrongAnswer(selection);
		}
		int rowCount = this.answerLogMapper.insertSelective(answerLog);
		if (rowCount == 0) {
			log.error("插入答题 日志表失败, answer_log");
			return ServerResponse.createByErrorMessage("服务器处理错误，请与管理员联系");

		}
		return ServerResponse.createBySuccess();
	}

	private QuestionCheckVo checkResult(UserBo userBo, List<Integer> optionList) {
		QuestionCheckVo vo = new QuestionCheckVo();

		Integer questionType = userBo.getQuestion().getType();
		List<Answer> answerList = userBo.getAnswerList();

		List<Answer> rightAnswerList = new ArrayList<>();
		vo.setRightAnswerList(rightAnswerList);

		// 首先对单选题，判断题作判断，查看用户的选择是否正确
		if (questionType == QuestionConst.Type.JUDGE.getCode() || questionType == QuestionConst.Type.SINGLE.getCode()) {
			answerList.forEach(answer -> {
				if (answer.getStatus() == QuestionConst.OptionStatus.RIGHT.getCode()) {
					rightAnswerList.add(answer);
					if (answer.getId().equals(optionList.get(0))) {
						// 用户选择正确
						vo.setCheckResult(QuestionConst.CheckResult.RIGHT.getCode());
						vo.setCheckResultMsg(QuestionConst.CheckResult.RIGHT.getValue());
					} else {
						vo.setCheckResult(QuestionConst.CheckResult.WRONG.getCode());
						vo.setCheckResultMsg(QuestionConst.CheckResult.WRONG.getValue());
					}
				}
			});
		} else {
			vo.setCheckResult(QuestionConst.CheckResult.RIGHT.getCode());
			vo.setCheckResultMsg(QuestionConst.CheckResult.RIGHT.getValue());
			// 题目为多选题时判断是否正确
			answerList.forEach(answer -> {
				if (answer.getStatus() == QuestionConst.OptionStatus.RIGHT.getCode()) {
					// 判断正确的答案用户是否选择了
					rightAnswerList.add(answer);
					if (!checkOption(optionList, answer.getId())) {
						vo.setCheckResult(QuestionConst.CheckResult.WRONG.getCode());
						vo.setCheckResultMsg(QuestionConst.CheckResult.WRONG.getValue());
					}
				} else {
					// 判断错误的答案用户是否选择了
					if (checkOption(optionList, answer.getId())) {
						vo.setCheckResult(QuestionConst.CheckResult.WRONG.getCode());
						vo.setCheckResultMsg(QuestionConst.CheckResult.WRONG.getValue());
					}
				}
			});
		}
		return vo;
	}

	private boolean checkOption(List<Integer> optionList, Integer id) {
		boolean selected = false;
		for (Integer option : optionList) {
			if (option.equals(id)) {
				selected = true;
			}
		}

		return selected;
	}

	@Override
	@Transactional
	public ServerResponse<?> readExcel() {
		ServerResponse<?> response = ServerResponse.createBySuccessMessage("导入成功");
		String fileName = "C:\\exam\\exam.xls";
		QuestionExcelListener listerner = new QuestionExcelListener();
		try {
			EasyExcel.read(fileName, QuestionExcelDto.class, listerner).sheet().doRead();
			List<QuestionDto> questionDtoList = listerner.getQuestionDtoList();
			for (QuestionDto dto : questionDtoList) {
				Question question = dto.assmbleQuestion();
				int rowCount = this.questionMapper.insertSelective(question);
				if (rowCount == 0) {
					log.error("insert question table error");
					throw new RuntimeException("插入question表失败");
				}
				List<Answer> answerList = dto.assmbleAnswerList(question.getId());
				rowCount = this.answerMapper.insertAnswerBatch(answerList);
				if (rowCount == 0) {
					log.error("insert answer table error");
					throw new RuntimeException("插入answer表失败");
				}
			}

		} catch (Exception e) {
			log.error(e.getStackTrace().toString());
			response = ServerResponse.createByErrorMessage(e.getCause().getMessage());
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
		}
		return response;
	}
}
